﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;
using System.Text;

namespace Titan.WinFormSys
{
    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        private static void Main()
        {
            //设置应用程序处理异常方式：ThreadException处理
            Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);
            //处理UI线程异常
            Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
            //处理非UI线程异常
            AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            AppSingle.Run(new FrmIndex(), new FrmMain());
        }


        static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
        {
            string str = GetExceptionMsg(e.Exception, e.ToString());
            MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            string str = GetExceptionMsg(e.ExceptionObject as Exception, e.ToString());

            MessageBox.Show(str, "系统错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        /// <summary>
        /// 生成自定义异常消息
        /// </summary>
        /// <param name="ex">异常对象</param>
        /// <param name="backStr">备用异常消息：当ex为null时有效</param>
        /// <returns>异常字符串文本</returns>
        static string GetExceptionMsg(Exception ex, string backStr)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("****************************异常文本****************************");
            sb.AppendLine("【出现时间】：" + DateTime.Now.ToString());
            if (ex != null)
            {
                sb.AppendLine("【异常类型】：" + ex.GetType().Name);
                sb.AppendLine("【异常信息】：" + ex.Message);
                sb.AppendLine("【堆栈调用】：" + ex.StackTrace);
            }
            else
            {
                sb.AppendLine("【未处理异常】：" + backStr);
            }
            sb.AppendLine("***************************************************************");
            return sb.ToString();
        }

        #region 进程单件类
        /// <summary>
        /// 进程单件类(实现程序只运行一个实例)
        /// </summary>
        internal sealed class AppSingle
        {
            /// <summary>
            /// 设置窗口的显示状态
            /// </summary>
            /// <param name="hWnd"></param>
            /// <param name="cmdShow"></param>
            /// <returns></returns>
            [DllImport("User32.dll")]
            private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);

            /// <summary>
            /// 将已经运行的进程的窗口设置到前台，并且激活该窗口
            /// </summary>
            /// <param name="hWnd"></param>
            /// <returns></returns>
            [DllImport("User32.dll")]
            private static extern bool SetForegroundWindow(IntPtr hWnd);

            /// <summary>
            /// 判断指定窗体是否已经最小化
            /// </summary>
            /// <param name="hWnd"></param>
            /// <returns></returns>
            [DllImport("user32.dll")]
            private static extern bool IsIconic(IntPtr hWnd);

            /// <summary>
            /// 实现单态实例的互斥量
            /// </summary>
            private static Mutex _appMutex;

            /// <summary>
            /// 启动程序
            /// </summary>
            /// <param name="splashForm">程序欢迎窗口</param>
            /// <param name="mainForm">程序主窗口</param>
            public static void Run(Form splashForm, Form mainForm)
            {
                Debug.Assert(mainForm != null);

                if (CreateMutex())
                {
                    Application.ApplicationExit += OnAppExit;

                    //欢迎窗口
                    if (splashForm != null)
                    {
                        if (splashForm.ShowDialog() == DialogResult.OK)
                        {
                            splashForm.Dispose();
                            //主窗口
                            Application.Run(mainForm);
                        }
                    }
                    else
                    {
                        //主窗口
                        Application.Run(mainForm);
                    }
                }
                else
                {
                    MessageBox.Show(@"程序已启动！", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    Process prcInstance = GetRunningProcessInstance();
                    if (prcInstance != null)
                    {
                        ShowRunningProcessInstance(prcInstance);
                    }
                }
            }

            /// <summary>   
            /// 获取已运行本程序的进程   
            /// </summary>   
            /// <returns></returns>   
            private static Process GetRunningProcessInstance()
            {
                var current = Process.GetCurrentProcess();
                var processes = Process.GetProcessesByName(current.ProcessName);
                return processes.FirstOrDefault(process => process.Id != current.Id && Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName);
            }

            /// <summary>   
            /// 将指定进程的的窗口设置到前台，并且激活该窗口程序窗口
            /// </summary>   
            /// <param name="proc"></param>   
            private static void ShowRunningProcessInstance(Process proc)
            {
                if (proc == null)
                {
                    return;
                }

                const int swShowna = 8; //以窗口的当前状态显示窗口并激活窗口
                const int swRestore = 9; //如果窗口已经最小化或最大化，以恢复到原来的尺寸和位置显示并激活窗口
                var showType = swShowna;
                if (IsIconic(proc.MainWindowHandle))
                {
                    showType = swRestore;
                }
                ShowWindowAsync(proc.MainWindowHandle, showType);

                //将已经运行的进程的窗口设置到前台，并且激活该窗口
                SetForegroundWindow(proc.MainWindowHandle);
            }

            /// <summary>
            /// 创建互斥对象
            /// </summary>
            /// <returns></returns>
            private static bool CreateMutex()
            {
                _appMutex = new Mutex(false, "Titan.SMS Mutext");
                return _appMutex.WaitOne(TimeSpan.Zero, false);
            }

            /// <summary>
            /// 释放互斥对象
            /// </summary>
            private static void ReleaseMutex()
            {
                if (_appMutex == null) return;
                _appMutex.ReleaseMutex();
                _appMutex.Close();
            }

            /// <summary>
            /// 程序退出之间的事件，用来删除互斥量
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="args"></param>
            private static void OnAppExit(object sender, EventArgs args)
            {
                ReleaseMutex();
            }
        }
        #endregion
    }
}
